/* Row.java
 * This class specifies a particular row, column, or diagonal on a grid.
 * In any winning row, each coordinate is either fixed, increasing or decreasing.
 * The "dim" variable is used to store the direction of each coordinate.
 * A -2 indicates a coordinate that is decreasing, a -1 indicates a coordinate that
 * is increasing, and a 0 indicates a coordinate that is fixed at that position.
 */
package tictactoe;

public class Row {
	public Row() {
		dim = new int[GameLogic.num_dimensions];
		for(int dimctr = 0; dimctr < GameLogic.num_dimensions; dimctr++) dim[dimctr] = -2;
		dim[0] = -1;
		//set dim to be the first number that has first non-fixed dimension increasing
		// this is -1,-2,...,-2
	}
	
	public Square getSquare(int ctr, int length) {
		// Gets the square of index ctr from the row, assuming each dimension in the board has length "length"
		return new Square(toCoord(dim[0],ctr,length),toCoord(dim[1],ctr,length),toCoord(dim[2],ctr,length),toCoord(dim[3],ctr,length));
	}
	
	public boolean next(int length) {
		// changes state to next non-redundant row
		// if the row wraps to the first row, return false
		// otherwise, return true
		increment(length);
		while(!valid()) increment(length);
		// -1,-2,...,-2 is the initial state
		// if this is not the current state, return true
		if(dim[0] != -1) return true;
		for(int index = 1; index < dim.length; index++)
		{
			if(dim[index] != -2) return true;
		}
		return false;
	}
	
	public boolean nextNonPlanar(int length) {
		// Gets the next row where there are more than two changing dimensions
		increment(length);
		while(!valid() || numChangingDimensions() < 3) increment(length);
		// -1,-2,...,-2 is the initial state and also the first 3 or more dimensional
		// state
		// if this is not the current state, return true
		if(dim[0] != -1) return true;
		for(int index = 1; index < dim.length; index++)
		{
			if(dim[index] != -2) return true;
		}
		return false;
	}
	
	private int numChangingDimensions() {
		// Returns the number of dimensions that do not change
		int count = 0;
		for(int index = 0; index < dim.length; index++) {
			if(dim[index] < 0) count++;
		}
		return count;
	}
	
	private boolean valid() {
		// returns true if the integers in dim correspond to a row with
		// first non-changing index increasing
		// the first non-changing index is required to be increasing to avoid creating
		// duplicates of the same row
		for(int i = 0; i < dim.length; i++) {
			if(dim[i] == -1) return true;
			if(dim[i] == -2) return false;
		}
		return false;
	}

	/* increment: sets dim to its lexicographical successor that allows the
	 * indices to range from -2 to length - 1
	 * for example: if length is 4, and dim holds [0,2,3,3,3], it would be changed
	 * to [0,3,-2,-2,-2]
	 */
	private void increment(int length) {

		int currdim = dim.length - 1;
		//Start with the last decimal place
		while(true) {
			// If currdim runs off the beginning of the array, break. The
			// lexicographic successor would overflow the array, and the value of dim
			// is now set to [-2,-2,..,-2], the lexicographically first number
			if(currdim == -1) break;
			// if the current dimension is not the maximum value,
			// increment it and return
			if(dim[currdim] < length - 1) {
				dim[currdim]++;
				break;
			}
			// if it is the maximum value, the number should carry to the next place in
			// the array and the current place should be set to -2
			else {
				dim[currdim] = -2;
				currdim--;
			}
		}
	}

	private int toCoord(int dim, int ctr, int length) {
		// Converts integers used to specify dimensions in player_wins to coordinates
		if (dim >= 0) return dim;
		if (dim == -1) return ctr;
		return length - 1 - ctr;
	}

	public boolean firstRow() {
		// -1,-2,...,-2 is the initial state
		// if this is not the current state, return true
		if(dim[0] != -1) return true;
		for(int index = 1; index < dim.length; index++)
		{
			if(dim[index] != -2) return true;
		}
		return false;
	}
	
	private int[] dim; // represents a row on the board
}
